#include "ThriftClient.hpp"
#include <spdlog/spdlog.h>
#include <nlohmann/json.hpp>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>

#define SEND_REQUEST(work) \
try { \
  std::lock_guard<std::mutex> lck(thriftMut); \
  work; \
} \
catch (const apache::thrift::TException& e) \
{ spdlog::error("ThriftClient error {} , exec: {}",e.what(),#work); }


void ThriftClient::Boot(std::string addr,int port)
{
  std::shared_ptr<apache::thrift::transport::TTransport> socket(new apache::thrift::transport::TSocket(addr, port));
  std::shared_ptr<apache::thrift::transport::TTransport> transport(new apache::thrift::transport::TBufferedTransport(socket));
  std::shared_ptr<apache::thrift::protocol::TProtocol> protocol(new apache::thrift::protocol::TBinaryProtocol(transport));
  client.reset(new Thrift::NodeClientClient(protocol));

  while(true)
  {
    try
    {
      transport->open();
      break;
    }
    catch(const apache::thrift::TException& e)
    {
      spdlog::warn("Client is not runing, wait 3s try again");
      std::this_thread::sleep_for(std::chrono::seconds(3));
    }
  }
}

std::vector<std::string> ThriftClient::GetDeviceList()
{
  std::set<std::string> rec;
  SEND_REQUEST(client->GetAllDevice(rec))
  std::vector<std::string> res;
  res.reserve(rec.size());
  for(const std::string & i : rec)
    res.push_back(i);
  return res;
}

void ThriftClient::SetSelectUUID(const std::string& uuid)
{
  controlUUID=uuid;
}


void ThriftClient::StartCollegeImage()
{
  SEND_REQUEST(client->StartShot(controlUUID));
}

void ThriftClient::StopCollegeImage()
{
  SEND_REQUEST(client->StopShot(controlUUID));
}

bool ThriftClient::GetCollegeImageStatus()
{
  SEND_REQUEST(return client->ShotStatus(controlUUID));
  return false;
}

void ThriftClient::SetImageSavePath(std::string path)
{
  savepath=path;
}


std::string ThriftClient::StartSaveImage()
{
  int count=1;
  while(true)
  {
    std::filesystem::path rpath=std::filesystem::path(savepath)/std::format("SM_{}",count);
    if(!std::filesystem::exists(rpath))
    {
      spdlog::info("File save path: {}",rpath.string());
      SEND_REQUEST(client->StartRecord(controlUUID,rpath.string(),2));
      break;
    }
    count++;
  }
  return "";
}

void ThriftClient::StopSaveImage()
{
  SEND_REQUEST(client->StopRecord(controlUUID));
}

bool ThriftClient::GetSaveImageStatus()
{
  SEND_REQUEST(return client->RecordStatus(controlUUID));
  return false;
}

void ThriftClient::SetImageFPSRate(long fps)
{
  nlohmann::json j=nlohmann::json::object();
  j["id"]=9;
  j["value"]=fps;
  j["type"]=1;
  SEND_REQUEST(client->SetSettingValue(controlUUID,j.dump()))
}


void ThriftClient::SetExposureTime(double time)
{
  nlohmann::json j=nlohmann::json::object();
  j["id"]=6;
  j["value"]=time;
  j["type"]=1;
  SEND_REQUEST(client->SetSettingValue(controlUUID,j.dump()))
}


double ThriftClient::GetExposureTime()
{
  std::string res;
  SEND_REQUEST(client->GetSettingValue(res,controlUUID,6));
  return nlohmann::json::parse(res)["value"].get<double>();
}


void ThriftClient::SetImageHeight(int64_t value)
{
  nlohmann::json j=nlohmann::json::object();
  j["id"]=2;
  j["value"]=value;
  j["type"]=0;
  SEND_REQUEST(client->SetSettingValue(controlUUID,j.dump()))
}

void ThriftClient::SetImageWidth(int64_t value)
{
  nlohmann::json j=nlohmann::json::object();
  j["id"]=3;
  j["value"]=value;
  j["type"]=0;
  SEND_REQUEST(client->SetSettingValue(controlUUID,j.dump()))
}

int64_t ThriftClient::GetImageHeight()
{
  std::string res;
  SEND_REQUEST(client->GetSettingValue(res,controlUUID,2));
  return nlohmann::json::parse(res)["value"].get<long>();
}

int64_t ThriftClient::GetImageWidth()
{
  std::string res;
  SEND_REQUEST(client->GetSettingValue(res,controlUUID,3));
  return nlohmann::json::parse(res)["value"].get<long>();
}

void ThriftClient::SetImageOffsetX(int64_t value)
{
  nlohmann::json j=nlohmann::json::object();
  j["id"]=4;
  j["value"]=value;
  j["type"]=0;
  SEND_REQUEST(client->SetSettingValue(controlUUID,j.dump()))
}

void ThriftClient::SetImageOffsetY(int64_t value)
{
  nlohmann::json j=nlohmann::json::object();
  j["id"]=5;
  j["value"]=value;
  j["type"]=0;
  SEND_REQUEST(client->SetSettingValue(controlUUID,j.dump()))
}

void ThriftClient::SetTriggerMode(bool value)
{
  nlohmann::json j=nlohmann::json::object();
  j["id"]=10;
  j["value"]=value ? 1 : 0;
  j["type"]=3;
  SEND_REQUEST(client->SetSettingValue(controlUUID,j.dump()))
}

int64_t ThriftClient::GetImageOffsetX()
{
  std::string res;
  SEND_REQUEST(client->GetSettingValue(res,controlUUID,4));
  return nlohmann::json::parse(res)["value"].get<long>();
}

int64_t ThriftClient::GetImageOffsetY()
{
  std::string res;
  SEND_REQUEST(client->GetSettingValue(res,controlUUID,5));
  return nlohmann::json::parse(res)["value"].get<long>();
}

double ThriftClient::GetCollegeFrameRate()
{
  std::string res;
  SEND_REQUEST(client->GetSettingValue(res,controlUUID,9));
  return nlohmann::json::parse(res)["value"].get<double>();
}

bool ThriftClient::GetTriggerMode()
{
  std::string res;
  SEND_REQUEST(client->GetSettingValue(res,controlUUID,10));
  return nlohmann::json::parse(res)["value"].get<int>() ? true : false;
}

#undef SEND_REQUEST
